package com.wfl.sampling.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wfl.sampling.config.WxPayConfig;
import com.wfl.sampling.entity.User;
import com.wfl.sampling.entity.WxchatOrderInformation;
import com.wfl.sampling.entity.WxchatPreOrder;
import com.wfl.sampling.entity.WxchatRefundInformation;
import com.wfl.sampling.handler.*;
import com.wfl.sampling.service.UserService;
import com.wfl.sampling.service.WxChatOrderService;
import com.wfl.sampling.service.WxPayService;
import com.wfl.sampling.service.WxchatSignService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//用于与微信端接口的交互
@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {
    //预下单地址
    private final static String PAY_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
    //退款地址
    private final static String REFUND_URL = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";
    @Autowired
    private WxchatSignService wxchatSignService;
    @Autowired
    private WxChatOrderService wxChatOrderService;
    @Autowired
    private UserService userService;
    @Autowired
    private WxPayConfig  wxPayConfig;

    //发起预下单请求并返回结果
    @Override
    public WxChatPayResponseInfo unifiedOrder(PayInRequestinfo payInRequestinfo, HttpServletRequest request) throws IOException, NoSuchAlgorithmException, SignatureException, InvalidKeyException, InvalidKeySpecException {
        //创建请求prepayRequest
        User userById = userService.getUserById(payInRequestinfo.getUser_id());
        JsapiReqPayerInfo payer = new JsapiReqPayerInfo(userById.getOpenId());
        payer.setOpenid(userById.getOpenId());
        CommReqAmountInfo commReqAmountInfo = new CommReqAmountInfo();
        commReqAmountInfo.setTotal(payInRequestinfo.getAmount());
        commReqAmountInfo.setCurrency("CNY");
        PayOutRequestInfo prepayRequest = new PayOutRequestInfo();
        prepayRequest.setPayer(payer);//设置支付人信息
        prepayRequest.setAmount(commReqAmountInfo);//获取订单金额信息
        prepayRequest.setOut_trade_no(WxPayConfig.getOuttradeNo());//设置订单号
        prepayRequest.setMchid(wxPayConfig.getMchId());// 设置应用号
        prepayRequest.setAppid(wxPayConfig.getAppId());// 设置商户号
        prepayRequest.setNotify_url(wxPayConfig.getOrder_notify_url());//设置支付回调地址
        prepayRequest.setDescription(payInRequestinfo.getDescription());
        // 生成请求签名
        JSONObject json = (JSONObject) JSONObject.toJSON(prepayRequest);
        WxChatResponseInfo wxChatResponseInfo = wxchatSignService.WxChatdoPay("POST", PAY_URL, json);
        WxChatPayResponseInfo wxChatPayResponseInfo = new WxChatPayResponseInfo();
        if(wxChatResponseInfo.getCode()==200){
            //封装主体数据
            wxChatPayResponseInfo.setCode(200);
            wxChatPayResponseInfo.setPackage("prepay_id=" + JSONObject.parseObject(wxChatResponseInfo.getResponseBody()).get("prepay_id"));
            wxChatPayResponseInfo.setTimeStamp(String.valueOf(System.currentTimeMillis()));
            wxChatPayResponseInfo.setNonceStr(WxPayConfig.getOuttradeNo());
            String messagePay = wxchatSignService.bulidMessagePay(wxPayConfig.getAppId(), wxChatPayResponseInfo.getNonceStr(), wxChatPayResponseInfo.getPackage(), wxChatPayResponseInfo.getTimeStamp());
            String paysign = wxchatSignService.sign(messagePay.getBytes(StandardCharsets.UTF_8));
            wxChatPayResponseInfo.setPaysign(paysign);
            wxChatPayResponseInfo.setSignType("RSA");
            //添加预下单表数据
            WxchatPreOrder wxchatPreOrder = new WxchatPreOrder();
//            wxchatPreOrder.setActivity_id(payInRequestinfo.getActivity_id());
            wxchatPreOrder.setOut_trade_no(prepayRequest.getOut_trade_no());
            wxchatPreOrder.setDescription(prepayRequest.getDescription());
            wxchatPreOrder.setTotal(prepayRequest.getAmount().getTotal());
            wxchatPreOrder.setOpenid(prepayRequest.getPayer().getOpenid());
            wxchatPreOrder.setState("NOTPAY");
            wxChatOrderService.savePreOrderAll(wxchatPreOrder);
            log.info("预下单成功");
        }else {
            wxChatPayResponseInfo.setCode(wxChatResponseInfo.getCode());
            log.info("预下单失败");
        }
        return wxChatPayResponseInfo;
    }



    //验证回调支付通知签名
    @Override
    public String verifySignatureOrder(HttpServletRequest request, HttpServletResponse response, Verifier verifier) throws IllegalAccessException {
        Gson gson = new Gson();
        final HashMap<String, Object> map = new HashMap<>();
        if(!wxchatSignService.wxPaySuccessCallback(request, response, verifier)){
            // 通知验签失败
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "通知验签失败");
            return gson.toJson(map);
        }
        final String body = WxPayConfig.getRequestBody(request);
        //添加订单表,修改下单表.
        WxchatOrderInformation wxchatOrderInformation = JSONObject.parseObject(wxchatSignService.Outbody(JSON.parseObject(body)), WxchatOrderInformation.class);
        ResponseOrderAmountInfo amount = (ResponseOrderAmountInfo) JSON.parseObject(wxchatSignService.Outbody(JSON.parseObject(body))).get("amount");
        wxchatOrderInformation.setTotal(amount.getTotal());
        wxchatOrderInformation.setPayer_total(amount.getPayer_total());
        Payer payer = (Payer) JSON.parseObject(wxchatSignService.Outbody(JSON.parseObject(body))).get("payer");
        wxchatOrderInformation.setOpenid(payer.getOpenid());
        wxChatOrderService.saveOrderAll(wxchatOrderInformation);
        wxChatOrderService.updatePreOrderState(wxchatOrderInformation.getTrade_state(),(String) JSON.parseObject(wxchatSignService.Outbody(JSONObject.parseObject(body))).get("out_trade_no"));
        //通知验签成功
        response.setStatus(200);
        map.put("code", "SUCCESS");
        map.put("message", "通知验签成功");
        return gson.toJson(map);
    }


    //用于查询支付结果并返回
    @Override
    public WxchatOrderInformation queryOrder(String id) throws MalformedURLException, UnsupportedEncodingException, URISyntaxException, NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException {
        WxchatOrderInformation orderById = wxChatOrderService.findOrderById(id);
        WxchatOrderInformation wxchatOrderInformation = new WxchatOrderInformation();
        WxChatResponseInfo wxChatResponseInfo = wxchatSignService.WxChatQuery("order", orderById.getOut_trade_no());
        if (wxChatResponseInfo.getCode() == 200) {
            //封装报文主体
            wxchatOrderInformation = JSONObject.parseObject(wxChatResponseInfo.getResponseBody(), WxchatOrderInformation.class);
            //根据state_desc来修改订单表，下单表
            wxChatOrderService.updatePreOrderState(wxchatOrderInformation.getTrade_state(),wxchatOrderInformation.getOut_trade_no());
            wxChatOrderService.updateOrder(wxchatOrderInformation.getOut_trade_no(),wxchatOrderInformation.getTrade_state());
        }
        return wxchatOrderInformation;
    }


    //关闭订单
    @Override
    public Map<String,Integer> Closeorder(String id) throws UnsupportedEncodingException, NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException {
        WxchatOrderInformation orderById = wxChatOrderService.findOrderById(id);
        Map<String, Integer> map = wxchatSignService.WxChatClose(orderById.getOut_trade_no());
        if (map.get("code") == 200) {
            //删除预下单表
            wxChatOrderService.deleteByOut_trade_no(orderById.getOut_trade_no());
        }
        return map;
    }


    //用于申请退款(前端传入out_refund_no,refund_fee）
    @Override
    public String refund(String param) throws UnsupportedEncodingException, NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException {
        //创建请求对象
        RefundOutRequestInfo refund = new RefundOutRequestInfo();
        refund.setOut_refund_no((String) JSONObject.parseObject(param).get("out_refund_no"));
        AmountReq amountReq =(AmountReq)((JSONObject.parseObject(param).get("refund_fee")));
        refund.setAmount(amountReq);
        refund.setNotify_url(wxPayConfig.getRefund_notify_url());
        //生成请求
        JSONObject json = (JSONObject) JSON.toJSON(refund);
        WxChatResponseInfo wxChatResponseInfo = wxchatSignService.WxChatdoPay("POST", REFUND_URL, json);
        if(wxChatResponseInfo.getCode() == 200){
            //封装报文主体
            Map<String,Object> jsonBody = JSONObject.parseObject(wxChatResponseInfo.getResponseBody());
            return (String) jsonBody.get("state");
        }else {
            return "服务器退款请求失败";
        }
    }

    //验证退款通知回调签名
    @Override
    public String verifySignatureRefund(HttpServletRequest request, HttpServletResponse response, Verifier verifier) throws IllegalAccessException {
        Gson gson = new Gson();
        final HashMap<String, Object> map = new HashMap<>();
        if (!wxchatSignService.wxPaySuccessCallback(request, response, verifier)) {
            // 通知验签失败
            response.setStatus(500);
            map.put("code", "ERROR");
            map.put("message", "通知验签失败");
            return gson.toJson(map);
        }
        final String body = WxPayConfig.getRequestBody(request);
        //用于添加退款表,修改下单表,订单表
        WxchatRefundInformation wxchatRefundInformation = JSONObject.parseObject(wxchatSignService.Outbody(JSON.parseObject(body)), WxchatRefundInformation.class);
        ResponseRefundAmountInfo amount = (ResponseRefundAmountInfo) JSON.parseObject(wxchatSignService.Outbody(JSON.parseObject(body))).get("amount");
        wxchatRefundInformation.setTotal(amount.getTotal());
        wxchatRefundInformation.setRefund(amount.getRefund());
        wxchatRefundInformation.setPayer_total(amount.getPayer_total());
        wxchatRefundInformation.setPayer_refund(amount.getPayer_refund());
        Payer payer = (Payer) JSON.parseObject(wxchatSignService.Outbody(JSON.parseObject(body))).get("payer");
        wxchatRefundInformation.setOpenid(payer.getOpenid());
        wxChatOrderService.saveRefundAll(wxchatRefundInformation);
        if(wxchatRefundInformation.getRefund_status().equals("SUCCESS")) {
            wxChatOrderService.updateOrder("REFUND", wxchatRefundInformation.getOut_trade_no());
            wxChatOrderService.updatePreOrderState("REFUND", wxchatRefundInformation.getOut_refund_no());
        }
        //通知验签成功
        response.setStatus(200);
        map.put("code", "SUCCESS");
        map.put("message", "通知验签成功");
        return gson.toJson(map);
    }


    //用于查询退款结果并返回
    @Override
    public WxchatRefundInformation queryRefund(String id) throws MalformedURLException, UnsupportedEncodingException, URISyntaxException, NoSuchAlgorithmException, SignatureException, InvalidKeySpecException, InvalidKeyException {
        // 创建请求对象
        WxchatRefundInformation refundById = wxChatOrderService.findRefundById(id);
        WxchatRefundInformation wxchatRefundInformation = new WxchatRefundInformation();
        WxChatResponseInfo wxChatResponseInfo = wxchatSignService.WxChatQuery("refund", refundById.getOut_refund_no());
        if (wxChatResponseInfo.getCode() == 200) {
            //封装报文主体
            wxchatRefundInformation = JSONObject.parseObject(wxChatResponseInfo.getResponseBody(), WxchatRefundInformation.class);
            String state = (String) JSON.parseObject(wxChatResponseInfo.getResponseBody()).get("state");
            wxchatRefundInformation.setRefund_status(state);
            //根据state_desc来修改订单表，下单表,退款表
            wxChatOrderService.updateRefund(wxchatRefundInformation.getOut_refund_no(), wxchatRefundInformation.getRefund_status(), String.valueOf(wxchatRefundInformation.getPayer_refund()));
            if(state.equals("SUCCESS")) {
                wxChatOrderService.updatePreOrderState("REFUND",wxchatRefundInformation.getOut_trade_no());
                wxChatOrderService.updateOrder(wxchatRefundInformation.getOut_trade_no(), "REFUND");
            }
        }
        return wxchatRefundInformation;
    }



    //查询预下单表并返回
    @Override
    public List<WxchatPreOrder> findPreOrders(int user_id){

        User user = userService.getUserById(user_id);
        return wxChatOrderService.findPreOrdersByOpenid(user.getOpenId());
    }
    //查询订单列表并返回
    @Override
    public List<WxchatOrderInformation> findOrders(int user_id){
        //查询数据库
        User user = userService.getUserById(user_id);
        return wxChatOrderService.findOrdersByOpenid(user.getOpenId(),"SUCCESS");
    }

    //查询退款列表并返回
    @Override
    public List<WxchatRefundInformation> findRefunds(int user_id){
        User user = userService.getUserById(user_id);
        return wxChatOrderService.findRefundsByOpenid(user.getOpenId());
    }
}
